﻿using System;
using System.Collections.Concurrent;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;

namespace eslib.nnp5.layers
{

    /// <summary>
    /// 数据包队列式发送控制器，需要收到ACK后继续发送数据包
    /// </summary>
    class SendControler : SendControlerBase
    {
        /// <summary>
        /// 待发送的数据包队列
        /// </summary>
        private ConcurrentQueue<TransferredPKG> dataPkgColl;

        /// <summary>
        /// 待发送的ack包队列
        /// </summary>
        private ConcurrentQueue<ACKPkg> ackPkgColl;

        /// <summary>
        /// 当前正在发送的数据包，发送结束后会置null
        /// </summary>
        private TransferredPKG CurrentPkg
        {
            get
            {
                lock (this)
                {
                    return curpkg;
                }
            }
            set
            {
                lock (this)
                {
                    curpkg = value;
                }
            }
        }
        TransferredPKG curpkg = null;



        /// <summary>
        /// 清空所有队列
        /// </summary>
        public override void ResetQueues()
        {
            dataPkgColl = new ConcurrentQueue<TransferredPKG>();
            ackPkgColl = new ConcurrentQueue<ACKPkg>();
            CurrentPkg = null;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="connector">通讯层连接对象</param>
        /// <param name="transportLayer">传输层对象</param>        
        public SendControler(Connector connector, TransportLayer transportLayer) : base(connector)
        {
            transportLayer.NewACKEvent += TransportLayer_NewACKEvent;
        }


        /// <summary>
        /// 新ack接收
        /// </summary>
        /// <param name="ack"></param>
        private void TransportLayer_NewACKEvent(ACKPkg ack)
        {
            if (CurrentPkg != null)
            {
                if (ack.getPkgID() == CurrentPkg.getPkgID())        //收到的ack与当前发送的包一致
                {
                    CurrentPkg = null;
                    sendNextDataPkg();      //发送下一个
                }
            }
        }






        /// <summary>
        /// 发送数据包
        /// </summary>
        /// <param name="pkg"></param>
        public override void sendDataPkg(TransferredPKG pkg)
        {
            //加入数据包队列
            dataPkgColl.Enqueue(pkg);

            //偿试发包
            trySendPkg();
        }






        /// <summary>
        /// 回送ack包
        /// </summary>
        /// <param name="pkgID"></param>
        public override void sendACKPkg(uint pkgID)
        {
            ACKPkg ack = ACKPkg.CreateSuccessACK(pkgID);
            ackPkgColl.Enqueue(ack);

            //偿试发包
            trySendPkg();
        }






        /// <summary>
        /// 发送下一个数据包
        /// </summary>
        private void sendNextDataPkg()
        {
            sendAllAckPkg();    //先发出所有ack包

            lock (this)
            {
                if (dataPkgColl.Count > 0)
                {
                    //从集合开头获取要发送的包
                    if (dataPkgColl.TryDequeue(out TransferredPKG pkg))
                    {
                        CurrentPkg = pkg;
                        connector.send(CurrentPkg.makePKG());
                    }
                }
            }
        }



        /// <summary>
        /// 偿试发送数据包
        /// </summary>
        void trySendPkg()
        {
            sendAllAckPkg();    //先发出所有ack包

            if (CurrentPkg == null)
            {
                sendNextDataPkg();
            }
            //非null说明发送正在工作
        }


        /// <summary>
        /// 发出所有ack包(线程同步)
        /// </summary>
        void sendAllAckPkg()
        {
            lock (this)
            {
                for (int i = 0; i < ackPkgColl.Count; i++)
                {
                    if (ackPkgColl.TryDequeue(out ACKPkg ack))
                    {
                        connector.send(ack.makePKG());
                    }
                }
            }
        }


    }

}
